﻿''' <summary>
''' Provides NLS functionality
''' </summary>
''' <remarks></remarks>
Public Class Localizer
    Inherits Dictionary(Of String, String)

    Private _languageID As Integer
    Private _provider As ITranslationProvider


    ''' <summary>
    ''' Gets the language ID. Can be 0 if Language has been set.
    ''' </summary>
    ''' 
    Public ReadOnly Property LanguageID As Integer
        Get
            Return _languageID
        End Get
    End Property


    ''' <summary>
    ''' Gets or sets the language name. Used only when user is editing NLS.
    ''' </summary>
    ''' 
    Public Property LanguageName As String

    ''' <summary>
    ''' Gets the NLS value provider
    ''' </summary>
    ''' 
    Public ReadOnly Property Provider As ITranslationProvider
        Get
            Return _provider
        End Get
    End Property


    Default Public Overloads ReadOnly Property Item(key As String, defaultValue As String) As String
        Get
            If Me.ContainsKey(key) Then
                Return Me(key)
            ElseIf defaultValue IsNot Nothing Then
                Me(key) = defaultValue
                Return defaultValue
            Else
                Return Me(key)
            End If
        End Get
    End Property

    ''' <summary>
    ''' Initializes a new instance of the <see cref="Localizer" /> class.
    ''' </summary>
    ''' <param name="provider">The provider.</param>
    Sub New(Optional provider As ITranslationProvider = Nothing)
        _languageID = _defLanguageID
        Me.LanguageName = _defLanguageName
        _provider = If(provider Is Nothing, _defProvider, provider)
    End Sub

    ''' <summary>
    ''' Initializes a new instance of the <see cref="Localizer" /> class.
    ''' </summary>
    ''' <param name="languageID">The language ID.</param>
    ''' <param name="languageName">Language name</param>
    ''' <param name="provider">The provider.</param>
    Sub New(languageID As Integer, languageName As String, Optional provider As ITranslationProvider = Nothing)
        _languageID = languageID
        Me.LanguageName = languageName
        _provider = If(provider Is Nothing, _defProvider, provider)
    End Sub

    ''' <summary>
    ''' Adds the key to be loaded by NLS.
    ''' </summary>
    ''' <param name="key">The translation key.</param>
    ''' <param name="defaultIfNotExists">The default if the key does not exists/is not translated.</param>
    Sub AddKey(key As String, Optional defaultIfNotExists As String = Nothing)
        If Not ContainsKey(key) Then
            Me(key) = If(defaultIfNotExists Is Nothing, key, defaultIfNotExists)
        End If
    End Sub

    ''' <summary>
    ''' Removes the key from NLS.
    ''' </summary>
    ''' <param name="key">The NLS key.</param>
    Sub RemoveKey(key As String)
        Me.Remove(key)
    End Sub

    ''' <summary>
    ''' Loads the all the added translation key values from data store.
    ''' </summary>
    Sub LoadTranslations()
        If _provider Is Nothing Or _languageID = 0 Then Exit Sub
        Dim loadedValues As IDictionary(Of String, String)
        loadedValues = _provider.LoadTranslations(_languageID, Me.Keys.ToArray())
        For Each kvp In loadedValues
            Me(kvp.Key) = kvp.Value
        Next
    End Sub


    ''' <summary>
    ''' Loads only the key values which were passed as parameters from data store.
    ''' </summary>
    ''' <param name="keys">The keys.</param>
    Sub LoadTranslationKeys(ParamArray keys() As String)
        If _provider Is Nothing Or _languageID = 0 Then Exit Sub
        Dim loadedValues As IDictionary(Of String, String)
        loadedValues = _provider.LoadTranslations(_languageID, keys)
        For Each kvp In loadedValues
            Me(kvp.Key) = kvp.Value
        Next
    End Sub


    ''' <summary>
    ''' Loads all translations which have the key which starts with the given string.
    ''' For example key: Test - would load Test.Something, TestSomethingElse, Test.another
    ''' </summary>
    ''' <param name="baseKey">The base key.</param>
    Sub LoadAllTranslationsWithBaseKey(baseKey As String)
        If _provider Is Nothing Or _languageID = 0 Then Exit Sub
        Dim loadedValues As IDictionary(Of String, String)
        loadedValues = _provider.LoadTranslationsByFilter(_languageID, baseKey + "%")
        For Each kvp In loadedValues
            Me(kvp.Key) = kvp.Value
        Next
    End Sub


    ''' <summary>
    ''' Updates the NLS value.
    ''' </summary>
    ''' <param name="key">The key.</param>
    ''' <param name="newValue">The new value.</param>
    Sub UpdateTranslation(key As String, newValue As String)
        If _provider Is Nothing Then
            Throw New InvalidOperationException("There is no translation provider configured. Either define provider in constructure or use Localizer.SetDefaults.")
        End If
        If _languageID <> 0 Then
            _provider.UpdateTranslation(_languageID, key, newValue)
        Else
            Throw New InvalidOperationException("You did not define a valid language.")
        End If
    End Sub

#Region "Shared methods"

    Private Shared _defLanguageID As Integer
    Private Shared _defLanguageName As String
    Private Shared _defProvider As ITranslationProvider

    ''' <summary>
    ''' Gets the default language ID.
    ''' </summary>
    ''' 
    Public Shared ReadOnly Property DefaultLanguageID As Integer
        Get
            Return _defLanguageID
        End Get
    End Property


    ''' <summary>
    ''' Gets the default provider.
    ''' </summary>
    ''' 
    Public Shared ReadOnly Property DefaultProvider As ITranslationProvider
        Get
            Return _defProvider
        End Get
    End Property

    ''' <summary>
    ''' Sets the defaults. Defaults will be automaticaly used by any newly created Nls instance.
    ''' Defaults can be overriden per Localizer instance, see Localizer constructors.
    ''' </summary>
    ''' <param name="languageID">The language ID.</param>
    ''' <param name="languageName">Language name</param>
    ''' <param name="provider">The provider.</param>
    Public Shared Sub SetDefaults(languageID As Integer, languageName As String, provider As ITranslationProvider)
        _defLanguageID = languageID
        _defLanguageName = languageName
        _defProvider = provider
    End Sub


    ''' <summary>
    ''' Gets the value for the given key.
    ''' </summary>
    ''' <param name="key">The key.</param>
    ''' <param name="defaultIfNotExists">The default value if not exists.</param>
    ''' <returns></returns>
    Public Shared Function GetValue(key As String, Optional defaultIfNotExists As String = Nothing) As String
        Return GetValueWithLanguage(key, _defLanguageID, defaultIfNotExists)
    End Function

    ''' <summary>
    ''' Gets the value for the given key and specific language ID.
    ''' </summary>
    ''' <param name="key">The key.</param>
    ''' <param name="languageID">The language ID.</param>
    ''' <param name="defaultIfNotExists">The default if not exists.</param>
    ''' <returns></returns>
    Public Shared Function GetValueWithLanguage(key As String, languageID As Integer, Optional defaultIfNotExists As String = Nothing) As String
        Dim n As New Localizer(languageID, Nothing)
        n.AddKey(key, defaultIfNotExists)
        n.LoadTranslations()
        Return n(key)
    End Function

    ''' <summary>
    ''' Merges the given localizers into one for easier nls management.
    ''' </summary>
    ''' <param name="localizers">The localizers.</param>
    ''' <returns></returns>
    Public Shared Function Merge(ParamArray localizers() As Localizer) As Localizer
        If localizers.Length = 0 Then Throw New ArgumentNullException("You have to provide at least one Localizer for merging")
        Dim languageID As Integer = localizers(0).LanguageID
        If localizers.Any(Function(n) n.LanguageID <> languageID) Then
            Throw New InvalidOperationException("You may not merge Localizer with different languages")
        End If
        Dim mergedLocalizer As New Localizer(localizers(0).LanguageID, localizers(0).LanguageName, localizers(0).Provider)
        For Each n In localizers
            For Each key In n.Keys
                mergedLocalizer(key) = n(key)
            Next
        Next
        Return mergedLocalizer
    End Function

#End Region

End Class
